package com.sqs.math;

/**
 * 分数类
 * 
 * @author sqs
 *
 */
public class Fraction extends Number implements Comparable<Fraction> {

	/**
	 * 
	 */
	private static final long serialVersionUID = -6504686159766611519L;

	private final int denominator;

	private final int numerator;

	/**
	 * 分数构造函数
	 * 
	 * @param denominator
	 *            分母,必须非零
	 * @param numerator
	 *            分子
	 */
	public Fraction(int denominator, int numerator) {
		if (denominator == 0) {
			throw new IllegalArgumentException("denominator must not be zero!");
		}

		boolean isNegative = false;
		if (numerator == 0) {
			isNegative = false;
		} else if (numerator < 0 && denominator < 0) {
			isNegative = false;
		} else if (numerator > 0 && denominator > 0) {
			isNegative = false;
		} else {
			isNegative = true;
		}

		this.denominator = java.lang.Math.abs(denominator);
		if (isNegative) {
			this.numerator = java.lang.Math.negateExact(java.lang.Math.abs(numerator));
		} else {
			this.numerator = java.lang.Math.abs(numerator);
		}

	}

	/**
	 * 分数相加,返回分数的最简形式
	 * 
	 * @param augend
	 * @return
	 */
	public Fraction add(Fraction augend) {
		int resultNumerator = this.numerator * augend.denominator + augend.numerator * this.denominator;
		int resultDenominator = this.denominator * augend.denominator;

		if (resultNumerator == 0) {
			return new Fraction(1, 0);
		}

		int gcd = Math.gcd(java.lang.Math.abs(resultNumerator), java.lang.Math.abs(resultDenominator));
		resultDenominator = resultDenominator / gcd;
		resultNumerator = resultNumerator / gcd;

		return new Fraction(resultDenominator, resultNumerator);
	}

	/**
	 * 分数相减,返回分数的最简形式
	 * 
	 * @param subtrahend
	 * @return
	 */
	public Fraction subtract(Fraction subtrahend) {
		int resultNumerator = this.numerator * subtrahend.denominator - subtrahend.numerator * this.denominator;
		int resultDenominator = this.denominator * subtrahend.denominator;

		if(resultNumerator==0) {
			return new Fraction(1, 0);
		}
		
		int gcd = Math.gcd(java.lang.Math.abs(resultNumerator), java.lang.Math.abs(resultDenominator));
		resultDenominator = resultDenominator / gcd;
		resultNumerator = resultNumerator / gcd;

		return new Fraction(resultDenominator, resultNumerator);
	}

	/**
	 * 分数相乘,返回分数的最简形式
	 * 
	 * @param multiplicand
	 * @return
	 */
	public Fraction multiply(Fraction multiplicand) {
		int resultNumerator = this.numerator * multiplicand.numerator;
		int resultDenominator = this.denominator * multiplicand.denominator;

		if (resultNumerator == 0) {
			return new Fraction(1, 0);
		}

		int gcd = Math.gcd(java.lang.Math.abs(resultNumerator), java.lang.Math.abs(resultDenominator));
		resultNumerator = resultNumerator / gcd;
		resultDenominator = resultDenominator / gcd;

		return new Fraction(resultDenominator, resultNumerator);
	}

	/**
	 * 分数相除,返回分数的最简形式
	 * 
	 * @param divisor
	 * @return
	 */
	public Fraction divide(Fraction divisor) {
		if (divisor.numerator == 0) {
			throw new IllegalArgumentException("divisor must not be 0");
		}

		int resultNumerator = this.numerator * divisor.denominator;
		int resultDenominator = this.denominator * divisor.numerator;

		if (resultNumerator == 0) {
			return new Fraction(1, 0);
		}

		int gcd = Math.gcd(java.lang.Math.abs(resultNumerator), java.lang.Math.abs(resultDenominator));
		resultNumerator = resultNumerator / gcd;
		resultDenominator = resultDenominator / gcd;

		return new Fraction(resultDenominator, resultNumerator);
	}

	public int compareTo(Fraction o) {
		return this.numerator * o.denominator - o.numerator * this.denominator;
	}

	@Override
	public int intValue() {
		return numerator / denominator;
	}

	@Override
	public long longValue() {
		return numerator / denominator;
	}

	@Override
	public float floatValue() {
		return (float) numerator / (float) denominator;
	}

	@Override
	public double doubleValue() {
		return (double) numerator / (double) denominator;
	}

	public int getDenominator() {
		return denominator;
	}

	public int getNumerator() {
		return numerator;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + denominator;
		result = prime * result + numerator;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Fraction other = (Fraction) obj;
		return this.compareTo(other) == 0;
	}

	@Override
	public String toString() {
		return "Fraction [" + numerator + "/" + denominator + "]";
	}

}
